package main

import(
	"crypto/tls"
	"crypto/x509"
	"encoding/base64"
	"fmt"
	"net/http"
	"os"
	"log"
	"encoding/csv"
	"context"
	"time"
	"sync"
	"io/ioutil"
)

// 外部目标服务器（server0.com）的ECH配置信息
var (
	echConfig = "AEb+DQBCewAgACBLqkoAzquxPXHR8LzH5qZCGo7oegXdBJgO+aTfP10qJAAMAAEAAQABAAIAAQADIAtzZXJ2ZXIwLmNvbQAA"
)

func main() {
	if len(os.Args) < 2 {
		log.Fatal("Usage: go run main.go <csv_file>")
	}
	csvFile := os.Args[1]

	// 打开url数据集文件
	file, err := os.Open(csvFile)
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	reader := csv.NewReader(file)
	var urls []string

	for {
		record, err := reader.Read()
		if err != nil {
			break
		}
		urls = append(urls, record[0])
	}

	// 使用 WaitGroup 控制并发，每次最多运行 3 个任务
	var wg sync.WaitGroup
	sem := make(chan struct{}, 3)

	for _, url := range urls {
		wg.Add(1)
		sem <- struct{}{} // 限制并发数

		go func(u string) {
			defer wg.Done()
			httpsClientStart(u)
			<-sem // 释放并发限制
			time.Sleep(500 * time.Millisecond)
		}(url)
	}

	wg.Wait()

}

func httpsClientStart(url string) {

	// 解码ECH配置
	echConfigListBytes, err := base64.StdEncoding.DecodeString(echConfig)
	if err != nil {
		fmt.Printf("Error decoding configlist %v", err)
		return
	}
	
	// 配置客户端证书
	caCert, err := ioutil.ReadFile("server1.crt")
	if err != nil {
		log.Fatal("读取CA证书失败:", err)
	}
	caCertPool := x509.NewCertPool()
	caCertPool.AppendCertsFromPEM(caCert)

	// 配置TLS
	tlsConfig := &tls.Config{
		MinVersion: tls.VersionTLS13,
		MaxVersion: tls.VersionTLS13,
		ServerName: "server1.com",
		EncryptedClientHelloConfigList: echConfigListBytes,
		RootCAs:    caCertPool,
	}

	// 创建http.client实例
	client := &http.Client{
		Transport: &http.Transport{
			TLSClientConfig: tlsConfig,
			DisableKeepAlives: true,
		},
	}

	// 创建一个5秒的超时上下文
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	// 构造代理请求
	proxyReq, _ := http.NewRequest("GET", "https://192.168.157.128:443/proxy", nil)
	proxyReq.Header.Set("X-Target-URL", url) // 设置目标URL
	proxyReq.WithContext(ctx)

	// 发送请求
	resp, err := client.Do(proxyReq)
	if err != nil {
		log.Printf("请求失败:", err)
		return
	}
	defer resp.Body.Close()

	// 读取响应
	body, _ := ioutil.ReadAll(resp.Body)
	fmt.Printf("请求url: %s\n",url)
	fmt.Printf("响应状态: %s\n内容:\n%s\n", resp.Status, body[:100])
}
